package com.emm.yixun.website.listeners;

import com.emm.yixun.common.enums.ResponseEnums;
import com.emm.yixun.common.model.*;
import com.emm.yixun.common.model.dto.*;
import com.emm.yixun.common.model.enums.*;
import com.emm.yixun.common.response.Response;
import com.emm.yixun.common.response.ResponseList;
import com.emm.yixun.common.utils.BeanUtil;
import com.emm.yixun.customer.service.*;
import com.emm.yixun.customer.service.channel.ChannelSendHttpMessageService;
import com.emm.yixun.estate.service.ProjectRoomServiceFacade;
import com.emm.yixun.marketing.service.BusinessAbnormaServiceFacade;
import com.emm.yixun.marketing.service.HaveReceiveRefundServiceFacade;
import com.emm.yixun.marketing.service.NeedReceiveRefundServiceFacade;
import com.emm.yixun.marketing.service.RoomChangeHistoryServiceFacade;
import com.emm.yixun.system.service.notice.subscribe.SubscribeRetreatNoticeFacade;
import com.emm.yixun.website.common.utils.SpringWebContextUtil;
import com.emm.yixun.website.common.utils.security.ShiroUtil;
import com.emm.yixun.website.service.ActivitiProcessServiceImpl;
import com.emm.yixun.website.service.system.log.ActCommitLogService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.springframework.beans.BeanUtils;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

public class SubscribeRetreatListeners implements Serializable, ExecutionListener {
	private static final long serialVersionUID = -5623735222280919582L;

	@Override
	public void notify(DelegateExecution execution) throws Exception {
		String businessAbnormaId = execution.getProcessBusinessKey();
		String processInstanceId = execution.getProcessInstanceId();
		BusinessAbnormaServiceFacade businessAbnormaServiceFacade = getBusinessAbnormaServiceFacade();
		Response<BusinessAbnorma> businessAbnormaResponse = businessAbnormaServiceFacade
				.findById(Long.valueOf(businessAbnormaId));
		if (!businessAbnormaResponse.isSuccess()) {
			throw new Exception("退认购记录不存在");
		}
		BusinessAbnorma businessAbnorma = businessAbnormaResponse.getEntity();
		if (null == businessAbnorma) {
			throw new Exception("退认购记录记录不存在");
		}

		SubscribeServiceFacade subscribeServiceFacade = getSubscribeServiceFacade();
		Response<Subscribe> payDepositResponse = subscribeServiceFacade.findById(businessAbnorma.getBusinessId());
		if (!payDepositResponse.isSuccess()) {
			throw new Exception("认购记录不存在");
		}
		Subscribe subscribe = payDepositResponse.getEntity();
		if (null == subscribe) {
			throw new Exception("认购记录不存在");
		}

		if (getActivitiProcessServiceImpl().isCheckPass(processInstanceId)) {

			boolean flag = checkAuditCommit(businessAbnorma);
			if (!flag) {
				throw new Exception(ResponseEnums.RESPONSEENUMS_999999.getName());
			}

			/**
			 * 原记录不做变更,只做第二状态 变更 2017-09-21
			 */
			// 认筹记录标示为解除认筹
			SubscribeDto updatePddDto = new SubscribeDto();
			updatePddDto.setId(subscribe.getId());
			updatePddDto.setBusinessStatus(SubscribeBusinessStatusEnum.SUBSCRIBE.getNo());
			updatePddDto.setBusinessSecStatus("5");
			Response<Integer> responseUudate = subscribeServiceFacade.updateByPrimaryKey(updatePddDto, true);
			if (!responseUudate.isSuccess()) {
				throw new Exception("认购第二状态变更失败!");
			}
			// 判断是否还有审核中或者审核通过的数据，以此来判断是否返回到可售
			PayDepositDto payDepositDto = new PayDepositDto();
			// 审核状态为审核中或已通过且业务状态为认筹或者更名(ym)
			payDepositDto.setM_auditStatus(" and t.audit_status in (1,3) and t.business_status in (1,4)");
			payDepositDto.setRoomId(subscribe.getRoomId());
			ResponseList<PayDeposit> responseList = getPayDepositServiceFacade().findByDtoJ(payDepositDto);
			// 房源状态为未售或者认筹
			if (responseList.getEntity() == null || responseList.getEntity().size() == 0) {
				ProjectRoomDto projectRoomDto = new ProjectRoomDto();
				projectRoomDto.setId(subscribe.getRoomId());
				projectRoomDto.setRoomStatus(RoomStatusEnum.VENDIBILITY.getNo());// 可售
				Response<Integer> responseRoomDto = getProjectRoomServiceFacade().updateByPrimaryKey(projectRoomDto,
						true);
				if (!responseRoomDto.isSuccess()) {
					throw new Exception("房间状态为可售出错");
				}
			} else {
				ProjectRoomDto projectRoomDto = new ProjectRoomDto();
				projectRoomDto.setId(subscribe.getRoomId());
				projectRoomDto.setRoomStatus(RoomStatusEnum.RESERVE.getNo());// 认筹
				Response<Integer> responseRoomDto = getProjectRoomServiceFacade().updateByPrimaryKey(projectRoomDto,
						true);
				if (!responseRoomDto.isSuccess()) {
					throw new Exception("房间状态为认筹出错");
				}
			}
			// 生成新的认购记录 认购状态为退认购

			SubscribeDto createNewSubscribe = new SubscribeDto();
			BeanUtil.convert2T(createNewSubscribe, subscribe);
			createNewSubscribe.setBusinessStatus("5");
			createNewSubscribe.setBusinessSecStatus("5");
			createNewSubscribe.setCheckDate(new Date());
			SubscribeDto addSub = subscribeServiceFacade.save(createNewSubscribe).getEntity();

			// 记录原认购房源变更记录
			RoomChangeHistoryDto dto = new RoomChangeHistoryDto();
			dto.setRoomId(subscribe.getRoomId());
			dto.setBusinessDynamics("退认购");
			dto.setRemark("房源由【认购】转为【可售】");
			dto.setBusinessHref("/customer/subscribe/toRetreatView?id=" + businessAbnorma.getId());
			dto.setMerchantId(subscribe.getMerchantId());
			dto.setAccessCode(subscribe.getAccessCode());
			dto.setCreateUserId(subscribe.getCreateUserId());
			dto.setUserCode(subscribe.getUserCode());
			dto.setDelFlag("0");
			dto.setUpdateUserId(subscribe.getUpdateUserId());
			dto.setUpdateTime(new Date());
			Response<RoomChangeHistoryDto> rchSaveResponse = getRoomChangeHistoryServiceFacade().save(dto);
			if (!rchSaveResponse.isSuccess()) {
				throw new Exception(rchSaveResponse.getResultMessage());
			}

			// 更新审核状态
			BusinessAbnormaDto updateDto = new BusinessAbnormaDto();
			updateDto.setId(businessAbnorma.getId());
			updateDto.setAuditStatus(AuditStatusEnum.SUCCESS.getNo());
			updateDto.setCheckDate(new Date());
			updateDto.setBusinessId(addSub.getId());
			Response<Integer> responseBusinessAbnormaDto = businessAbnormaServiceFacade.updateByPrimaryKey(updateDto,
					true);
			if (!responseBusinessAbnormaDto.isSuccess()) {
				throw new Exception("更新退筹审核状态出错");
			}

			// 经纪人关联
			TransactionRelationDto relationDto = new TransactionRelationDto();
			relationDto.setBusinessId(subscribe.getId());
			relationDto.setRelationType(SubscribeBusinessStatusEnum.REFUNDSUBSCRIPTION.getNo());
			ResponseList<TransactionRelation> responseRelationList = getTransactionRelationServiceFacade()
					.findByDto(relationDto);
			if (responseRelationList.getEntity() != null) {
				for (TransactionRelation rela : responseRelationList.getEntity()) {
					TransactionRelationDto addRelation = new TransactionRelationDto();
					BeanUtil.convert2T(addRelation, rela);
					addRelation.setBusinessId(addSub.getId());
					getTransactionRelationServiceFacade().save(addRelation);
				}
			}

			// 当收款金额大于0时，生成待退款记录 （对应为新认购下面的退款）
			BigDecimal totalAmount = findHaveAmountByDto(subscribe.getId());
			if (totalAmount.compareTo(new BigDecimal("0")) > 0) {
				// 记录应退款记录
				NeedReceiveRefundDto needReceiveRefundDto = new NeedReceiveRefundDto();
				needReceiveRefundDto.setRelationId(addSub.getId());
				needReceiveRefundDto.setBusinessType("1");
				needReceiveRefundDto.setTotalReceivablesAmount(totalAmount); // 发生额
				needReceiveRefundDto.setCustomerId(subscribe.getCustomerId());
				needReceiveRefundDto.setRoomId(subscribe.getRoomId());
				needReceiveRefundDto.setStatus("1");
				needReceiveRefundDto.setPostponedStatus("0");
				needReceiveRefundDto.setDocType("1");
				needReceiveRefundDto.setRemark("退认购款");
				needReceiveRefundDto.setHousingFundType(HousingFundTypeEnum.FUNDTYPE_4.getNo());
				needReceiveRefundDto.setBusinessFlag(BusinessFlagEnum.BUSINESSFLAG_8.getNo());
				needReceiveRefundDto.setPostponedStatus("0");

				needReceiveRefundDto.setMerchantId(subscribe.getMerchantId());
				needReceiveRefundDto.setUserCode(subscribe.getUserCode());
				needReceiveRefundDto.setAccessCode(subscribe.getAccessCode());
				needReceiveRefundDto.setCreateUserId(subscribe.getCreateUserId());
				needReceiveRefundDto.setDelFlag("0");
				needReceiveRefundDto.setUpdateUserId(subscribe.getUpdateUserId());
				needReceiveRefundDto.setUpdateTime(new Date());
				Response<NeedReceiveRefundDto> nrrdSaveResponse = getNeedReceiveRefundServiceFacade()
						.save(needReceiveRefundDto);
				if (!nrrdSaveResponse.isSuccess()) {
					throw new Exception(nrrdSaveResponse.getResultMessage());
				}

				/**
				 * 2017-08-11 增加自动退款功能 退款审核成功后，待退款直接变成已退款，不需要用户操作
				 */
				NeedReceiveRefundDto needDto = nrrdSaveResponse.getEntity();
				Boolean haveFlag = refund(needDto);
				if (!haveFlag) {
					throw new Exception("自动退款功能执行失败");
				}
			}

			/**
			 * 2017-08-11 判断是否已存在待收款记录 如有待收款记录，则删除
			 */
			Boolean needFlag = isDelByDto(subscribe.getId());
			if (!needFlag) {
				throw new Exception("删除待收款记录失败");
			}

			/**
			 * 删除认购相关伪签约信息
			 */
			delSubTransAmountByDto(subscribe.getId());

			/**
			 * 查询客户业务状态，并同步更新客户状态
			 */
			CustomerServiceFacade customerServiceFacade = getCustomerServiceFacade();
			String busStatus = customerServiceFacade.queryCustomerBusiness(subscribe.getCustomerId());
			CustomerDto cusDto = new CustomerDto();
			cusDto.setId(subscribe.getCustomerId());
			if (busStatus != null) {
				CustomerStatusEnum customer = CustomerStatusEnum.getByDescription(busStatus);
				if (customer == null) {
					throw new Exception("客户状态异常!");
				}
				cusDto.setCustomerStatus(customer.getNo());
				Response<Integer> responseCusDto = customerServiceFacade.updateByPrimaryKey(cusDto, true);
				if (!responseCusDto.isSuccess()) {
					throw new Exception("客户状态更新出错");
				}
			} else {
				Response<Customer> customerEntity = customerServiceFacade.findById(subscribe.getCustomerId());
				if (customerEntity.getEntity().getCustomerStatusBk() == null) {
					cusDto.setCustomerStatus(CustomerStatusEnum.VISIT.getNo());
				} else {
					cusDto.setCustomerStatus(customerEntity.getEntity().getCustomerStatusBk());
				}
				Response<Integer> responseCusDto = customerServiceFacade.updateByPrimaryKey(cusDto, true);
				if (!responseCusDto.isSuccess()) {
					throw new Exception("客户状态更新出错");
				}
			}

			/**
			 * 推送到渠道
			 */
			getChannelSendHttpMessageService().sendTransaction(subscribe.getId(), TransTypeEnum.SUBSCRIBE.getNo(), true);

			customerServiceFacade.changeCustomerLevel(subscribe.getCustomerId(), IntentionLevelEnum.C.getNo());

			/**
			 * （退认购审核通过）推送消息到app
			 * 
			 * @author ny
			 * @param param
			 *            noticeType 提醒类型, noticeBusinessId 业务主键Id
			 * @return 【${auditStatus}】房号：${roomName}；客户：${customer};
			 */
			NoticeEntity noticeEntity = new NoticeEntity();
			noticeEntity.setNoticeBusinessId(subscribe.getId());
			noticeEntity.setNoticeType("4");
			noticeEntity.setProcessInstanceId(processInstanceId);
			getSubscribeRetreatNoticeFacade().createSubscribeRetreatNotice(noticeEntity);
		} else {

			boolean flag = checkAuditCommit(businessAbnorma);
			if (!flag) {
				throw new Exception(ResponseEnums.RESPONSEENUMS_999999.getName());
			}

			// 更新审核状态
			BusinessAbnormaDto updateDto = new BusinessAbnormaDto();
			updateDto.setId(businessAbnorma.getId());
			updateDto.setAuditStatus(AuditStatusEnum.REJECT.getNo());
			updateDto.setCheckDate(new Date());
			Response<Integer> responseBusinessAbnormaDto = businessAbnormaServiceFacade.updateByPrimaryKey(updateDto,
					true);
			if (!responseBusinessAbnormaDto.isSuccess()) {
				throw new Exception("更新退认购审核状态出错");
			}

			/**
			 * （退认购审核不通过）推送消息到app
			 * 
			 * @author ny
			 * @param param
			 *            noticeType 提醒类型, noticeBusinessId 业务主键Id
			 * @return 【${auditStatus}】房号：${roomName}；客户：${customer};
			 */
			NoticeEntity noticeEntity = new NoticeEntity();
			noticeEntity.setNoticeBusinessId(subscribe.getId());
			noticeEntity.setNoticeType("4");
			noticeEntity.setProcessInstanceId(processInstanceId);
			getSubscribeRetreatNoticeFacade().createSubscribeRetreatNotice(noticeEntity);
		}
	}

	/**
	 * 2017-08-11 增加自动退款功能 退款审核成功后，待退款直接变成已退款，不需要用户操作
	 */
	private boolean refund(NeedReceiveRefundDto dto) {
		User user = ShiroUtil.getCurrentUser();
		HaveReceiveRefundDto entity = new HaveReceiveRefundDto();
		BeanUtils.copyProperties(dto, entity);
		entity.setId(null);
		entity.setReceivablesType(dto.getBusinessType()); // 业务类型
		entity.setRelationId(dto.getRelationId());// 业务ID
		entity.setReceivablesId(dto.getId()); // 应收款ID
		entity.setDeductibleAmount(new BigDecimal("0")); // 抵扣金额
		entity.setTransferStatus("0"); // 转账状态 0 正常 1 已转账
		entity.setOpSource("0");
		entity.setBankAccount("默认工商银行-6221234567890"); // 银行账号
		entity.setStatementId(1L); // 结算人员
		if(null != user) {
			entity.setStatementId(user.getId()); // 结算人员
		}
		entity.setStatementType(Long.parseLong(StatementTypeEnum.CASH.getNo())); // 结算类型
		entity.setDocType("1"); // 已退款
		entity.setReChecked("0"); // 未复核
		entity.setStatementDate(new Date()); // 结算日期

		boolean flag = getHaveReceiveRefundServiceFacade().addRefund(entity, dto.getId(), new BigDecimal("0"),
				dto.getTotalReceivablesAmount(), "need");
		return flag;
	}

	/**
	 * 2017-08-11 判断是否已存在待收款记录 如有待收款记录，则删除
	 */
	private boolean isDelByDto(Long id) {
		NeedReceiveRefundDto dto = new NeedReceiveRefundDto();
		dto.setRelationId(id); // 认购ID
		dto.setBusinessType(ReceivablesTypeEnum.SUBSCRIBE.getNo()); // 认购
		dto.setStatus(NeedStatusEnum.NO.getNo()); // 未结清
		dto.setDocType(DocTypeEnum.COLLECTION.getNo()); // 待收款
		dto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		boolean flag = getNeedReceiveRefundServiceFacade().isDelByDto(dto);

		return flag;
	}

	/**
	 * 2017-8-31 判断是否存在未签约及认购合同金额收款 如有，则删除
	 */
	private void delSubTransAmountByDto(Long id) {
		SubscribeTransDto stDto = new SubscribeTransDto();
		stDto.setSubId(id);
		ResponseList<SubscribeTrans> stResList = getSubscribeTransServiceFacade().findByDto(stDto);
		if (stResList.isSuccess()) {
			List<SubscribeTrans> stList = stResList.getEntity();
			if (null != stList && stList.size() > 0) {
				SubscribeTrans st = stList.get(0);
				long signedId = st.getSigId();
				// 退掉伪签约下合同金额收款
				HaveReceiveRefundDto hrrDto = new HaveReceiveRefundDto();
				hrrDto.setRelationId(signedId);
				ResponseList<HaveReceiveRefund> hrrResList = getHaveReceiveRefundServiceFacade().findByDto(hrrDto);
				if (hrrResList.isSuccess()) {
					List<HaveReceiveRefund> hrrList = hrrResList.getEntity();
					if (null != hrrList && hrrList.size() > 0) {
						for (HaveReceiveRefund hrr : hrrList) {
							hrrDto = new HaveReceiveRefundDto();
							hrrDto.setId(hrr.getId());
							hrrDto.setDelFlag(DelFlagEnum.DEL.getNo());
							hrrDto.setRemark("退认购操作: 删除伪签约已收款");
							getHaveReceiveRefundServiceFacade().updateByPrimaryKey(hrrDto, true);
						}
					}
				}
				// 伪签约代收款转成待退款
				NeedReceiveRefundDto nrrDto = new NeedReceiveRefundDto();
				nrrDto.setRelationId(signedId);
				ResponseList<NeedReceiveRefund> nrrResList = getNeedReceiveRefundServiceFacade().findByDto(nrrDto);
				if (nrrResList.isSuccess()) {
					List<NeedReceiveRefund> nrrList = nrrResList.getEntity();
					if (null != nrrList && nrrList.size() > 0) {
						for (NeedReceiveRefund nrr : nrrList) {
							nrrDto = new NeedReceiveRefundDto();
							nrrDto.setId(nrr.getId());
							nrrDto.setDelFlag(DelFlagEnum.DEL.getNo());
							nrrDto.setRemark("退认购操作: 删除伪签约代收款");
							getNeedReceiveRefundServiceFacade().updateByPrimaryKey(nrrDto, true);
						}
					}
				}
				// 伪签约改成已退房
				SignedDto signedDto = new SignedDto();
				signedDto.setId(signedId);
				signedDto.setDelFlag(DelFlagEnum.DEL.getNo());
				signedDto.setRemark("退认购操作: 删除伪签约");
				getSignedServiceFacade().updateByPrimaryKey(signedDto, true);
			}
		}
	}

	/**
	 * 2017-08-15 查询已收款金额 当金额为0时，表示未收款
	 */
	private BigDecimal findHaveAmountByDto(Long id) {
		BigDecimal amount = new BigDecimal("0");
		HaveReceiveRefundDto dto = new HaveReceiveRefundDto();
		dto.setRelationId(id); // 认购ID
		dto.setReceivablesType(ReceivablesTypeEnum.SUBSCRIBE.getNo()); // 认购标识
		dto.setDocType("0"); // 已收款
		dto.setTransferStatus("0"); // 正常
		Response<BigDecimal> response = getHaveReceiveRefundServiceFacade().findHaveAmountByDto(dto);
		if (response.isSuccess()) {
			amount = response.getEntity();
		}
		return amount;
	}

	/**
	 * 前置判断,审核记录是否已经提交,防止重复提交 产生原因: 提交审核,后台处理中时,刷新页面再次提交审核,会重复 true: 可继续执行 false:
	 * 不可执行
	 */
	public boolean checkAuditCommit(BusinessAbnorma entity) {
		// 业务数据为null时,默认通过.为了不改变老业务,不影响流程正常行走
		if (null == entity) {
			return true;
		}
		return getActcommitLogService().checkActCommit(entity.getAuditStatus(), entity.getMerchantId(), entity.getId(),
				entity.getProcInstId(), "退认购", "PC");
	}

	private ActCommitLogService getActcommitLogService() {
		return (ActCommitLogService) SpringWebContextUtil.getApplicationContext().getBean("actCommitLogService");
	}

	private CustomerServiceFacade getCustomerServiceFacade() {
		return (CustomerServiceFacade) SpringWebContextUtil.getApplicationContext().getBean("customerServiceFacade");
	}

	private SubscribeRetreatNoticeFacade getSubscribeRetreatNoticeFacade() {
		return (SubscribeRetreatNoticeFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("subscribeRetreatNoticeFacade");
	}

	private BusinessAbnormaServiceFacade getBusinessAbnormaServiceFacade() {
		return (BusinessAbnormaServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("businessAbnormaServiceFacade");
	}

	private NeedReceiveRefundServiceFacade getNeedReceiveRefundServiceFacade() {
		return (NeedReceiveRefundServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("needReceiveRefundServiceFacade");
	}

	private HaveReceiveRefundServiceFacade getHaveReceiveRefundServiceFacade() {
		return (HaveReceiveRefundServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("haveReceiveRefundServiceFacade");
	}

	private ActivitiProcessServiceImpl getActivitiProcessServiceImpl() {
		return (ActivitiProcessServiceImpl) SpringWebContextUtil.getApplicationContext()
				.getBean("activitiProcessServiceImpl");
	}

	private SubscribeServiceFacade getSubscribeServiceFacade() {
		return (SubscribeServiceFacade) SpringWebContextUtil.getApplicationContext().getBean("subscribeServiceFacade");
	}

	private ProjectRoomServiceFacade getProjectRoomServiceFacade() {
		return (ProjectRoomServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("projectRoomServiceFacade");
	}

	private RoomChangeHistoryServiceFacade getRoomChangeHistoryServiceFacade() {
		return (RoomChangeHistoryServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("roomChangeHistoryServiceFacade");
	}

	private PayDepositServiceFacade getPayDepositServiceFacade() {
		return (PayDepositServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("payDepositServiceFacade");
	}

	private SubscribeTransServiceFacade getSubscribeTransServiceFacade() {
		return (SubscribeTransServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("subscribeTransServiceFacade");
	}

	private SignedServiceFacade getSignedServiceFacade() {
		return (SignedServiceFacade) SpringWebContextUtil.getApplicationContext().getBean("signedServiceFacade");
	}

	private TransactionRelationServiceFacade getTransactionRelationServiceFacade() {
		return (TransactionRelationServiceFacade) SpringWebContextUtil.getApplicationContext()
				.getBean("transactionRelationServiceFacade");
	}

	private ChannelSendHttpMessageService getChannelSendHttpMessageService(){
		return (ChannelSendHttpMessageService)SpringWebContextUtil.getApplicationContext().getBean("channelSendHttpMessageService");
	}
}
